<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="shardingsphere">
      ShardingSphere 语句解析生成初探
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      在上篇文章中，我们找到了一个逻辑SQL转换到真实SQL的关键路径代码，本篇文中，我们就上篇基础上，来探索语句解析生成的一些细节
     </p>
     <h2 id="_2">
      源码解析
     </h2>
     <p>
      语句的关键解析生成的代码如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@RequiredArgsConstructor</span>
<span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractSQLBuilder</span> <span class="kd">implements</span> <span class="n">SQLBuilder</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">SQLRewriteContext</span> <span class="n">context</span><span class="p">;</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kd">final</span> <span class="n">String</span> <span class="nf">toSQL</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">isEmpty</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">();</span>
        <span class="p">}</span>
        <span class="n">Collections</span><span class="p">.</span><span class="na">sort</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">());</span>
        <span class="n">StringBuilder</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="p">();</span>
        <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">get</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="na">getStartIndex</span><span class="p">());</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">SQLToken</span> <span class="n">each</span> <span class="p">:</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">each</span> <span class="k">instanceof</span> <span class="n">ComposableSQLToken</span> <span class="o">?</span> <span class="n">getComposableSQLTokenText</span><span class="p">((</span><span class="n">ComposableSQLToken</span><span class="p">)</span> <span class="n">each</span><span class="p">)</span> <span class="p">:</span> <span class="n">getSQLTokenText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">getConjunctionText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="kd">protected</span> <span class="kd">abstract</span> <span class="n">String</span> <span class="nf">getSQLTokenText</span><span class="p">(</span><span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">);</span>

    <span class="kd">private</span> <span class="n">String</span> <span class="nf">getComposableSQLTokenText</span><span class="p">(</span><span class="kd">final</span> <span class="n">ComposableSQLToken</span> <span class="n">composableSQLToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">StringBuilder</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="p">();</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">SQLToken</span> <span class="n">each</span> <span class="p">:</span> <span class="n">composableSQLToken</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">getSQLTokenText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">getConjunctionText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">String</span> <span class="nf">getConjunctionText</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">substring</span><span class="p">(</span><span class="n">getStartIndex</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">),</span> <span class="n">getStopIndex</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">int</span> <span class="nf">getStartIndex</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">startIndex</span> <span class="o">=</span> <span class="n">sqlToken</span> <span class="k">instanceof</span> <span class="n">Substitutable</span> <span class="o">?</span> <span class="p">((</span><span class="n">Substitutable</span><span class="p">)</span> <span class="n">sqlToken</span><span class="p">).</span><span class="na">getStopIndex</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">sqlToken</span><span class="p">.</span><span class="na">getStartIndex</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">Math</span><span class="p">.</span><span class="na">min</span><span class="p">(</span><span class="n">startIndex</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">length</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">int</span> <span class="nf">getStopIndex</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">currentSQLTokenIndex</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">indexOf</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">==</span> <span class="n">currentSQLTokenIndex</span> <span class="o">?</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">length</span><span class="p">()</span> <span class="p">:</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">get</span><span class="p">(</span><span class="n">currentSQLTokenIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="na">getStartIndex</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      从toSQL函数可以看到，基本都死用context变量里面去获取生成真实SQL的，其内容大致如下：
     </p>
     <p>
      <img alt="image.png" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b6434f202d84280bd66cb016bfb0e14~tplv-k3u1fbpfcp-watermark.image"/>
     </p>
     <p>
      其他的TableToken比较丰富，包含了很多的信息，可能是逻辑表名需要转成真实表名，所有需要这么多的信息
     </p>
     <p>
      我们看到context.getSqlTokens()的长度是2，那result的就会经过三次添加：
     </p>
     <ul>
      <li>
       未循环遍历处理前的初始添加：result.append(context.getSql(), 0, context.getSqlTokens().get(0).getStartIndex());
      </li>
      <li>
       第一次循环添加： TableToken
      </li>
      <li>
       第二次循环添加：
      </li>
      <li>
       第三次循环添加
      </li>
     </ul>
     <p>
      下面我们就仔细跟下这三次添加
     </p>
     <h3 id="_3">
      初始添加
     </h3>
     <div class="codehilite">
      <pre><span></span><code><span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">get</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="na">getStartIndex</span><span class="p">());</span>
</code></pre>
     </div>
     <p>
      上面的语句就是从字符串中截取子字符串添加，从原始的SQL截取的，起点是0，结束点是第一个SQLTokens的startIndex
     </p>
     <p>
      相应的变化如下：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO
      </li>
     </ul>
     <p>
      这步感觉对于所有的SQL来说确实是通用的，前面这种语句应该都是不用进行解析变换的（如何获取截取的结束点，这个是SQLToken的生成部分，这次先不看，先跟一下处理流程）
     </p>
     <h3 id="tabletoken">
      第一次循环添加： TableToken
     </h3>
     <div class="codehilite">
      <pre><span></span><code>        <span class="k">for</span> <span class="p">(</span><span class="n">SQLToken</span> <span class="n">each</span> <span class="p">:</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">each</span> <span class="k">instanceof</span> <span class="n">ComposableSQLToken</span> <span class="o">?</span> <span class="n">getComposableSQLTokenText</span><span class="p">((</span><span class="n">ComposableSQLToken</span><span class="p">)</span> <span class="n">each</span><span class="p">)</span> <span class="p">:</span> <span class="n">getSQLTokenText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
            <span class="n">result</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">getConjunctionText</span><span class="p">(</span><span class="n">each</span><span class="p">));</span>
        <span class="p">}</span>
</code></pre>
     </div>
     <p>
      从上面的语句看出，目前有两种处理方式：
     </p>
     <ul>
      <li>
       组合SQLToken的处理： getComposableSQLTokenText
      </li>
      <li>
       非组合SQLToken的处理： getSQLTokenText
      </li>
     </ul>
     <p>
      我们跟踪得到直接走的： getSQLTokenText
     </p>
     <p>
      跟踪进入下面的函数，如果是 RouteUnitAware,还需要进行处理
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">RouteSQLBuilder</span> <span class="kd">extends</span> <span class="n">AbstractSQLBuilder</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="n">String</span> <span class="nf">getSQLTokenText</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">sqlToken</span> <span class="k">instanceof</span> <span class="n">RouteUnitAware</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="p">((</span><span class="n">RouteUnitAware</span><span class="p">)</span> <span class="n">sqlToken</span><span class="p">).</span><span class="na">toString</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">sqlToken</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      看看TableToken是如何ToString的，相关的细节如下
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">TableToken</span> <span class="kd">extends</span> <span class="n">SQLToken</span> <span class="kd">implements</span> <span class="n">Substitutable</span><span class="p">,</span> <span class="n">RouteUnitAware</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="p">(</span><span class="kd">final</span> <span class="n">RouteUnit</span> <span class="n">routeUnit</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// 得到了真实的表名，真实表名从逻辑表到真实表的转换Map中获取的</span>
        <span class="n">String</span> <span class="n">actualTableName</span> <span class="o">=</span> <span class="n">getLogicAndActualTables</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">).</span><span class="na">get</span><span class="p">(</span><span class="n">tableName</span><span class="p">.</span><span class="na">getValue</span><span class="p">().</span><span class="na">toLowerCase</span><span class="p">());</span>
    <span class="c1">// 如果真实表名是null，则获取tableName的值（还能这么写成一句，学到了）</span>
    <span class="c1">// tableName是value值是原始的SQL的 t_order</span>
        <span class="n">actualTableName</span> <span class="o">=</span> <span class="kc">null</span> <span class="o">==</span> <span class="n">actualTableName</span> <span class="o">?</span> <span class="n">tableName</span><span class="p">.</span><span class="na">getValue</span><span class="p">().</span><span class="na">toLowerCase</span><span class="p">()</span> <span class="p">:</span> <span class="n">actualTableName</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">tableName</span><span class="p">.</span><span class="na">getQuoteCharacter</span><span class="p">().</span><span class="na">wrap</span><span class="p">(</span><span class="n">actualTableName</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// 从下面的函数大意就可以看出是构建逻辑表名到真实表的映射转换Map </span>
    <span class="kd">private</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="nf">getLogicAndActualTables</span><span class="p">(</span><span class="kd">final</span> <span class="n">RouteUnit</span> <span class="n">routeUnit</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Collection</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">tableNames</span> <span class="o">=</span> <span class="n">sqlStatementContext</span><span class="p">.</span><span class="na">getTablesContext</span><span class="p">().</span><span class="na">getTableNames</span><span class="p">();</span>
        <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HashMap</span><span class="o">&lt;&gt;</span><span class="p">(</span><span class="n">tableNames</span><span class="p">.</span><span class="na">size</span><span class="p">(),</span> <span class="mi">1</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">RouteMapper</span> <span class="n">each</span> <span class="p">:</span> <span class="n">routeUnit</span><span class="p">.</span><span class="na">getTableMappers</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">result</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">each</span><span class="p">.</span><span class="na">getLogicName</span><span class="p">().</span><span class="na">toLowerCase</span><span class="p">(),</span> <span class="n">each</span><span class="p">.</span><span class="na">getActualName</span><span class="p">());</span>
        <span class="c1">// 为啥还要再加一次，这里没有理解</span>
            <span class="n">result</span><span class="p">.</span><span class="na">putAll</span><span class="p">(</span><span class="n">shardingRule</span><span class="p">.</span><span class="na">getLogicAndActualTablesFromBindingTable</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">.</span><span class="na">getDataSourceMapper</span><span class="p">().</span><span class="na">getLogicName</span><span class="p">(),</span> <span class="n">each</span><span class="p">.</span><span class="na">getLogicName</span><span class="p">(),</span> <span class="n">each</span><span class="p">.</span><span class="na">getActualName</span><span class="p">(),</span> <span class="n">tableNames</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      return tableName.getQuoteCharacter().wrap(actualTableName) 核心代码大致如下,额外的加一些东西（关键字保留字段处理之类的？）
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Getter</span>
<span class="kd">public</span> <span class="kd">enum</span> <span class="n">QuoteCharacter</span> <span class="p">{</span>

    <span class="n">BACK_QUOTE</span><span class="p">(</span><span class="s">"`"</span><span class="p">,</span> <span class="s">"`"</span><span class="p">),</span>

    <span class="n">SINGLE_QUOTE</span><span class="p">(</span><span class="s">"'"</span><span class="p">,</span> <span class="s">"'"</span><span class="p">),</span>

    <span class="n">QUOTE</span><span class="p">(</span><span class="s">"\""</span><span class="p">,</span> <span class="s">"\""</span><span class="p">),</span>

    <span class="n">BRACKETS</span><span class="p">(</span><span class="s">"["</span><span class="p">,</span> <span class="s">"]"</span><span class="p">),</span>

    <span class="n">NONE</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">);</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">startDelimiter</span><span class="p">;</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">endDelimiter</span><span class="p">;</span>

    <span class="cm">/**</span>
<span class="cm">     * Wrap value with quote character.</span>
<span class="cm">     * </span>
<span class="cm">     * @param value value to be wrapped</span>
<span class="cm">     * @return wrapped value</span>
<span class="cm">     */</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">wrap</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">startDelimiter</span> <span class="o">+</span> <span class="n">value</span> <span class="o">+</span> <span class="n">endDelimiter</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      相应的变化如下：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0
      </li>
     </ul>
     <p>
      下面来到: result.append(getConjunctionText(each));
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractSQLBuilder</span> <span class="kd">implements</span> <span class="n">SQLBuilder</span> <span class="p">{</span>
    <span class="kd">private</span> <span class="n">String</span> <span class="nf">getConjunctionText</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">substring</span><span class="p">(</span><span class="n">getStartIndex</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">),</span> <span class="n">getStopIndex</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">int</span> <span class="nf">getStartIndex</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">startIndex</span> <span class="o">=</span> <span class="n">sqlToken</span> <span class="k">instanceof</span> <span class="n">Substitutable</span> <span class="o">?</span> <span class="p">((</span><span class="n">Substitutable</span><span class="p">)</span> <span class="n">sqlToken</span><span class="p">).</span><span class="na">getStopIndex</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">sqlToken</span><span class="p">.</span><span class="na">getStartIndex</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">Math</span><span class="p">.</span><span class="na">min</span><span class="p">(</span><span class="n">startIndex</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">length</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">int</span> <span class="nf">getStopIndex</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">currentSQLTokenIndex</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">indexOf</span><span class="p">(</span><span class="n">sqlToken</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">==</span> <span class="n">currentSQLTokenIndex</span> <span class="o">?</span> <span class="n">context</span><span class="p">.</span><span class="na">getSql</span><span class="p">().</span><span class="na">length</span><span class="p">()</span> <span class="p">:</span> <span class="n">context</span><span class="p">.</span><span class="na">getSqlTokens</span><span class="p">().</span><span class="na">get</span><span class="p">(</span><span class="n">currentSQLTokenIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="na">getStartIndex</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      大意就是获取开始和结束截取点，算法目前还没领会......，但和SQLToken的关系很大，看后面看SQLToken的时候能不能得到解答
     </p>
     <p>
      相应的变化如下：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status
      </li>
     </ul>
     <h3 id="_4">
      第二次循环添加：
     </h3>
     <p>
      我们看看第二次循环添加：GeneratedKeyInsertColumnToken
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="n">String</span> <span class="nf">getSQLTokenText</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">sqlToken</span> <span class="k">instanceof</span> <span class="n">RouteUnitAware</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="p">((</span><span class="n">RouteUnitAware</span><span class="p">)</span> <span class="n">sqlToken</span><span class="p">).</span><span class="na">toString</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="c1">// 直接走的这</span>
        <span class="k">return</span> <span class="n">sqlToken</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span>  <span class="nc">extends</span> <span class="n">SQLToken</span> <span class="kd">implements</span> <span class="n">Attachable</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 简单粗暴的直接插入一列名</span>
        <span class="k">return</span> <span class="n">String</span><span class="p">.</span><span class="na">format</span><span class="p">(</span><span class="s">", %s"</span><span class="p">,</span> <span class="n">column</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      从上面的大意看出，就是插入一列名，相应的变化如下：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status, order_id
      </li>
     </ul>
     <p>
      接着: result.append(getConjunctionText(each))，变成：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status, order_id) VALUES
      </li>
     </ul>
     <h3 id="_5">
      第三次循环添加:
     </h3>
     <p>
      我们接着看第三次循环添加：ShardingInsertValuesToken
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">RouteSQLBuilder</span> <span class="kd">extends</span> <span class="n">AbstractSQLBuilder</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="n">String</span> <span class="nf">getSQLTokenText</span><span class="p">(</span><span class="kd">final</span> <span class="n">SQLToken</span> <span class="n">sqlToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">sqlToken</span> <span class="k">instanceof</span> <span class="n">RouteUnitAware</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 走的这</span>
            <span class="k">return</span> <span class="p">((</span><span class="n">RouteUnitAware</span><span class="p">)</span> <span class="n">sqlToken</span><span class="p">).</span><span class="na">toString</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">sqlToken</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">ShardingInsertValuesToken</span> <span class="kd">extends</span> <span class="n">InsertValuesToken</span> <span class="kd">implements</span> <span class="n">RouteUnitAware</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="nf">ShardingInsertValuesToken</span><span class="p">(</span><span class="kd">final</span> <span class="kt">int</span> <span class="n">startIndex</span><span class="p">,</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">stopIndex</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">super</span><span class="p">(</span><span class="n">startIndex</span><span class="p">,</span> <span class="n">stopIndex</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="p">(</span><span class="kd">final</span> <span class="n">RouteUnit</span> <span class="n">routeUnit</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">StringBuilder</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="p">();</span>
    <span class="c1">// 这里得到了：(?, ?, ?, ?)，</span>
        <span class="n">appendInsertValue</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
    <span class="c1">// 然后又变成了：(?, ?, ?, ?)</span>
        <span class="n">result</span><span class="p">.</span><span class="na">delete</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="na">length</span><span class="p">()</span> <span class="o">-</span> <span class="mi">2</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="na">length</span><span class="p">());</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="na">toString</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">appendInsertValue</span><span class="p">(</span><span class="kd">final</span> <span class="n">RouteUnit</span> <span class="n">routeUnit</span><span class="p">,</span> <span class="kd">final</span> <span class="n">StringBuilder</span> <span class="n">stringBuilder</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">InsertValue</span> <span class="n">each</span> <span class="p">:</span> <span class="n">getInsertValues</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">isAppend</span><span class="p">(</span><span class="n">routeUnit</span><span class="p">,</span> <span class="p">(</span><span class="n">ShardingInsertValue</span><span class="p">)</span> <span class="n">each</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">stringBuilder</span><span class="p">.</span><span class="na">append</span><span class="p">(</span><span class="n">each</span><span class="p">).</span><span class="na">append</span><span class="p">(</span><span class="s">", "</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">isAppend</span><span class="p">(</span><span class="kd">final</span> <span class="n">RouteUnit</span> <span class="n">routeUnit</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ShardingInsertValue</span> <span class="n">insertValueToken</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">insertValueToken</span><span class="p">.</span><span class="na">getDataNodes</span><span class="p">().</span><span class="na">isEmpty</span><span class="p">()</span> <span class="o">||</span> <span class="kc">null</span> <span class="o">==</span> <span class="n">routeUnit</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">DataNode</span> <span class="n">each</span> <span class="p">:</span> <span class="n">insertValueToken</span><span class="p">.</span><span class="na">getDataNodes</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">routeUnit</span><span class="p">.</span><span class="na">findTableMapper</span><span class="p">(</span><span class="n">each</span><span class="p">.</span><span class="na">getDataSourceName</span><span class="p">(),</span> <span class="n">each</span><span class="p">.</span><span class="na">getTableName</span><span class="p">()).</span><span class="na">isPresent</span><span class="p">())</span> <span class="p">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      对于这个目前不懂，为啥要经过这个处理，应用场景是啥？
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status, order_id) VALUES (?, ?, ?, ?)
      </li>
     </ul>
     <p>
      接着: result.append(getConjunctionText(each))，变成：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status, order_id) VALUES (?, ?, ?, ?)
      </li>
     </ul>
     <p>
      到这里就解析生成完毕了
     </p>
     <h2 id="_6">
      总结
     </h2>
     <p>
      本篇中详细查看了逻辑SQL转真实SQL的处理过程：
     </p>
     <ul>
      <li>
       原始逻辑SQL： INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)
      </li>
      <li>
       result从空字符串变成了： INSERT INTO t_order_0 (user_id, address_id, status, order_id) VALUES (?, ?, ?, ?)
      </li>
     </ul>
     <p>
      转换中使用了相应的Token类进行对应的处理，组装成真实的SQL
     </p>
     <p>
      但算法之类的，目前还是不甚了解的，后面找找官方资料，有没有这方面的
     </p>
     <p>
      下面应该要去看看SQLToken的生成了，通过上面的跟踪发现，真实SQL的生成和SQLToken是息息相关的
     </p>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
